﻿namespace SEED.SEEDModels {
    using System;
    using System.Collections.Generic;
    /* 备注0：
     * 以下类唯一真正的目的是为所有子类定义公共字段和成员。
     * 无论如何，都不希望任何人创建这些类的直接实例，原因
     * 是这些类本身是一个非常一般的概念，可以通过使用abstract
     * 关键字来实现这一点，即抽象类防止直接的实例化。
     */
    #region Base block for all blockettes
    public abstract class Block {
        #region Field fof Block class
        private byte[] blockType = new byte[3];//3B;Standard blockette type identification number;
        #endregion
        #region Properties of Block class
        //注：这里使用了.NET 3.5或更高版本的自动属性。
        //关于自动属性的更多信息请查看有关书籍，其他类似地方不再赘述！
        public Int32 LenOfBlock { get; set; } //4B;Length of the entire blockette(including the 7 bytes in properties 1 and 2.)
        public byte[] BlockType {
            get {
                return this.blockType;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len; ;
                for (int i = 0; i < len; i++) {
                    //这里其实还有len<3的情况，但该情况不用显示处理，
                    //因为系统会自动将blockType[len+1]至blockType[3-1]置默认值0,其他类似的地方不再赘述。
                    this.blockType[i] = value[i];
                }
            }
        }
        #endregion
        #region Contructors of Block class
        public Block() { }
        public Block(byte[] blockType, Int32 lenOfBlock) {
            //注：这里为什么不用this.blockType = _blockType而使用this.BlockType = blockType呢？
            //因为我们赋值的控制逻辑都写在属性的set函数里面，在set中才使用blockType字段。所以
            //应该使用属性接收构造函数的参数而不是字段，如果使用字段接收，可能会发生溢出。其他类似的地方不再赘述！
            this.BlockType  = blockType;
            this.LenOfBlock = lenOfBlock;
        }
        #endregion
    }
    #endregion

    #region A class[Named IndentBlock] for X-Indentifier(X=station,location,channel)
    public abstract class IndentBlock : Block {
        #region Fields of IndentBlock
        private char[] staIdentifier = new char[5]; //Station identifier; 5-Bytes
        private char[] locIdentifier = new char[2]; //Location identifier;2-Bytes
        private char[] chaIdentifier = new char[3]; //Channel identifier; 3-Bytes
        #endregion

        #region Properties of IndentBlock
        public string StaIdentifier {
            get {
                string _StaIdentifier = new string(staIdentifier);
                return _StaIdentifier;
            }
            set {
                int len = value.Length;
                char[] str = new char[len];
                str = value.ToCharArray();
                len = (len > 5) ? 5 : len;
                for (int i = 0; i < len; i++) {
                    staIdentifier[i] = str[i];
                }
            }
        }
        public string LocIdentifier {
            get {
                string _LocIdentifier = new string(locIdentifier);
                return _LocIdentifier;
            }
            set {
                int len = value.Length;
                char[] str = new char[len];
                str = value.ToCharArray();
                len = (len > 2) ? 2 : len;
                for (int i = 0; i < len; i++) {
                    locIdentifier[i] = str[i];
                }
            }
        }
        public string ChaIdentifier {
            get {
                string _ChaIdertifier = new string(chaIdentifier);
                return _ChaIdertifier;
            }
            set {
                int len = value.Length;
                char[] str = new char[len];
                str = value.ToCharArray();
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    chaIdentifier[i] = str[i];
                }
            }
        }
        #endregion

        #region Constructors of IndentBlock
        public IndentBlock() { }
        public IndentBlock(
            byte[] blockType,
            Int32 lenOfBlock,
            string staIdentifier,
            string locIdentifier,
            string chaIdentifier
            )
            : base(blockType, lenOfBlock) {
            this.StaIdentifier = staIdentifier;
            this.LocIdentifier = locIdentifier;
            this.ChaIdentifier = chaIdentifier;
        }
        #endregion
    }
    #endregion

    #region A class[Named RptIndentBlock] for blockettes which contain numbers of X-Indentifier(X=station,location,channel)
    public abstract class RptIndentBlock : Block {
        #region Fields of RptIndentBlock
        private List<char[]> staIdentifier = new List<char[]>();
        private List<char[]> locIdentifier = new List<char[]>();
        private List<char[]> chaIdentifier = new List<char[]>();
        private int NumOfCompts;
        #endregion

        #region Properties of RptIndentBlock
        public List<char[]> StaIdentifier {
            get {
                return staIdentifier;
            }
            set {
                for (int i = 0; i < NumOfCompts; i++) {
                    //注释掉的达不到变长的效果,应该在确定[变长度]之后才申明变量
                    //char[] stationIdent = new char[5];
                    int len = value[i].Length;
                    len = (len > 5) ? 5 : len;
                    char[] stationIdent = new char[len];
                    for (int j = 0; j < len; j++) {
                        stationIdent[j] = value[i][j];
                    }
                    this.staIdentifier.Add(stationIdent);
                }
            }
        }
        public List<char[]> LocIdentifier {
            get {
                return locIdentifier;
            }
            set {
                for (int i = 0; i < NumOfCompts; i++) {
                    int len = value[i].Length;
                    len = (len > 2) ? 2 : len;
                    char[] locIndet = new char[len];
                    for (int j = 0; j < len; j++) {
                        locIndet[j] = value[i][j];
                    }
                    this.locIdentifier.Add(locIndet);
                }
            }
        }
        public List<char[]> ChaIdentifier {
            get {
                return chaIdentifier;
            }
            set {
                for (int i = 0; i < NumOfCompts; i++) {
                    int len = value[i].Length;
                    len = (len > 3) ? 3 : len;
                    char[] chaIdent = new char[len];
                    for (int j = 0; j < len; j++) {
                        chaIdent[j] = value[i][j];
                    }
                    this.chaIdentifier.Add(chaIdent);
                }
            }
        }
        #endregion

        #region Constructors of RptIndentBlock
        public RptIndentBlock() { }
        public RptIndentBlock(
            byte[] blockType,
            Int32 lenOfBlock,
            int   numOfCompts,
            List<char[]> staIdentifier,
            List<char[]> locIdentifier,
            List<char[]> chaIdentifier
            )
            : base(blockType, lenOfBlock) {
                this.StaIdentifier = staIdentifier;
                this.LocIdentifier = locIdentifier;
                this.ChaIdentifier = chaIdentifier;
                this.NumOfCompts   = numOfCompts;
        }
        #endregion
    }
    #endregion

    #region A class[Named Polynomial] for blockettes which contain Polynomial information
    public abstract class Polynomial : Block {
        #region fields of Polynomial
        private byte[]  stageSignalInputUnits   = new byte[3]; //3B;D-Type;
        private byte[]  stageSignalOutputUnits  = new byte[3]; //3B;D-Type;
        private byte[]  numOfPolyCoefficient    = new byte[3]; //3B;D-Type
        private float[] lowerValidFreqBound     = new float[3];//12B;F-Type
        private float[] upperValidFreqBound     = new float[3];//12B;F-Type
        private float[] lowerBoundOfApprox      = new float[3];//12B;F-Type
        private float[] upperBoundOfApprox      = new float[3];//12B;F-Type
        private float[] maxAbsoluteError        = new float[3];//12B;F-Type
        private List<float[]> polyCoefficient         = new List<float[]>();//12B;F-Type
        private List<float[]> polyCoefficentError     = new List<float[]>();//12B;F-Type
        #endregion

        #region properties of Block062
        public char TransferFuncType { get; set; }//Transfer Function Type:1B
        public char PolyApproxType   { get; set; }//Polynomial Approximation Type:1B
        public char ValidFreqUnits   { get; set; }//Valid Frequency Units:1B
        public byte[] StageSignalInputUnits       {
            get {
                return this.stageSignalInputUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.stageSignalInputUnits[i] = value[i];
                }
            }
        }
        public byte[] StageSignalOutputUnits      {
            get {
                return this.stageSignalOutputUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.stageSignalOutputUnits[i] = value[i];
                }
            }
        }
        public byte[]    NumOfPolyCoefficient     {
            get {
                return this.numOfPolyCoefficient;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.numOfPolyCoefficient[i] = value[i];
                }
            }
        }
        public float[]   LowerValidFreqBound    {
            get {
                return this.lowerValidFreqBound;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.lowerValidFreqBound[i] = value[i];
                }
            }
        }
        public float[]   UpperValidFreqBound    {
            get {
                return this.upperValidFreqBound;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.upperValidFreqBound[i] = value[i];
                }
            }
        }
        public float[]   LowerBoundOfApprox   {
            get {
                return this.lowerBoundOfApprox;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.lowerBoundOfApprox[i] = value[i];
                }
            }
        }
        public float[]   UpperBoundOfApprox   {
            get {
                return this.upperBoundOfApprox;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.upperBoundOfApprox[i] = value[i];
                }
            }
        }
        public float[]   MaxAbsoluteError            {
            get {
                return this.maxAbsoluteError;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.maxAbsoluteError[i] = value[i];
                }
            }
        }
        public List<float[]>   PolyCoefficient       {
            get {
                return this.polyCoefficient;
            }
            set {
                string str = "";
                for (int k = 0; k < NumOfPolyCoefficient.Length; k++) {
                    str += numOfPolyCoefficient[k].ToString();
                }
                int count = int.Parse(str);
                for (int index = 0; index < count; index++) {
                    float[] polyCoefficient = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        polyCoefficient[i] = value[index][i];
                    }
                    this.PolyCoefficient.Add(polyCoefficient);
                }
            }
        }
        public List<float[]>   PolyCoefficentError         {
            get {
                return this.polyCoefficentError;
            }
            set {
                string str = "";
                for (int k = 0; k < NumOfPolyCoefficient.Length; k++) {
                    str += numOfPolyCoefficient[k].ToString();
                }
                int count = int.Parse(str);
                for (int index = 0; index < count; index++) {
                    float[] polyCoefficientError = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        polyCoefficientError[i] = value[index][i];
                    }
                    this.PolyCoefficient.Add(polyCoefficientError);
                }
            }
        }
        #endregion

        #region constructors of Block062
        public Polynomial() { }
        public Polynomial(
            byte[]  blockType,
            Int32   lenOfBlock, 
            char    transFuncType, 
            byte[]  _stageSignalInutUnits,
            byte[]  _stageSignalOutputUnites, 
            char    polyApproxType, 
            char    validFreqUnits, 
            float[] _lowerValidFreqBound, 
            float[] _upperValidFreqBound,
            float[] _lowerBoundOfApprox, 
            float[] _upperBoundOfApprox, 
            float[] _maxAbsoluteError, 
            byte[]  _numOfPolyCoeffi, 
            List<float[]> _polyCoeffi, 
            List<float[]> _polyCoeffiError
            )
            :base(blockType,lenOfBlock){
                this.TransferFuncType       = transFuncType;
                this.stageSignalInputUnits  = _stageSignalInutUnits;
                this.stageSignalOutputUnits = _stageSignalOutputUnites;
                this.PolyApproxType         = polyApproxType;
                this.ValidFreqUnits         = validFreqUnits;
                this.lowerValidFreqBound    = _lowerValidFreqBound;
                this.upperValidFreqBound    = _upperValidFreqBound;
                this.lowerBoundOfApprox     = _lowerBoundOfApprox;
                this.upperBoundOfApprox     = _upperBoundOfApprox;
                this.maxAbsoluteError       = _maxAbsoluteError;
                this.numOfPolyCoefficient   = _numOfPolyCoeffi;
                this.polyCoefficient        = _polyCoeffi;
                this.polyCoefficentError    = _polyCoeffiError;
        }
        #endregion
    }
    #endregion

    #region A class[Named PolesNZeros] for blockettes which contain Poles & Zeros information
    public abstract class PolesNZeros : Block {
        #region fields of Poles & Zeros
        private byte[]   _stageSignalInUnits        = new byte[3]; //3B;D-Type
        private byte[]   _stageSignalOutUnits       = new byte[3]; //3B;D-Type
        private float[]  aONormalizationFactor      = new float[3];//12B;F-Type
        private float[]  normalizationFreq          = new float[3];//12B;F-Type
        private byte[]   numOfComplexZeros          = new byte[3]; //3B;D-Type;
        private byte[]   numOfCompexPoles           = new byte[3]; //3B;D-Type
        private List<float[]>  realZero             = new List<float[]>();//12B;F-Type
        private List<float[]>  imaginaryZero        = new List<float[]>();//12B;F-Type
        private List<float[]>  realZeroError        = new List<float[]>();//12B;F-Type
        private List<float[]>  imaginaryZeroError   = new List<float[]>();//12B;F-Type
        private List<float[]>  realPole             = new List<float[]>();//12B;F-Type
        private List<float[]>  imaginaryPole        = new List<float[]>();//12B;F-Type
        private List<float[]>  realPoleError        = new List<float[]>();//12B;F-Type
        private List<float[]>  imaginaryPoleError   = new List<float[]>();//12B;F-Type
        #endregion

        #region properties of Poles & Zeros
        private int cZeroCount {
            get {
                if (BitConverter.IsLittleEndian)
                    Array.Reverse(numOfComplexZeros);
                return BitConverter.ToInt32(numOfComplexZeros, 0);
            }
        }
        private int cPolesCount {
            get {
                if (BitConverter.IsLittleEndian)
                    Array.Reverse(numOfCompexPoles);
                return BitConverter.ToInt32(numOfCompexPoles, 0);
            }
        }
        public byte[] StageSignalInUnits {
            get {
                return this._stageSignalInUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this._stageSignalInUnits[i] = value[i];
                }
            }
        }
        public byte[] StageSignalOutUnits {
            get {
                return this._stageSignalOutUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this._stageSignalOutUnits[i] = value[i];
                }
            }
        }
        public byte[] NumOfComplexZeros {
            get {
                return this.numOfComplexZeros;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.numOfComplexZeros[i] = value[i];
                }
            }
        }
        public byte[] NumOfComplexPoles {
            get {
                return this.numOfCompexPoles;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.numOfCompexPoles[i] = value[i];
                }
            }
        }
        public float[] AONormalizationFactor {
            get {
                return this.aONormalizationFactor;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.aONormalizationFactor[i] = value[i];
                }
            }
        }
        public float[] NormalizationFreq {
            get {
                return this.normalizationFreq;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.normalizationFreq[i] = value[i];
                }
            }
        }
        public List<float[]> RealZero {
            get {
                return this.realPole;
            }
            set {
                for (int index = 0; index < cZeroCount; index++) {
                    float[] rPole = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        rPole[i] = value[index][i];
                    }
                    this.realZero.Add(rPole);
                }
            }
        }
        public List<float[]> ImaginaryZero {
            get {
                return this.imaginaryZero;
            }
            set {
                for (int index = 0; index < cZeroCount; index++) {
                    float[] iZero = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        iZero[i] = value[index][i];
                    }
                    this.imaginaryZero.Add(iZero);
                }
            }
        }
        public List<float[]> RealZeroError {
            get {
                return this.realZeroError;
            }
            set {
                for (int index = 0; index < cZeroCount; index++) {
                    float[] rZError = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        rZError[i] = value[index][i];
                    }
                    this.realZeroError.Add(rZError);
                }
            }
        }
        public List<float[]> ImaginaryZeroError {
            get {
                return this.imaginaryPoleError;
            }
            set {
                for (int index = 0; index < cZeroCount; index++) {
                    float[] iPError = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        iPError[i] = value[index][i];
                    }
                    this.imaginaryZeroError.Add(iPError);
                }
            }
        }
        public List<float[]> RealPole {
            get {
                return this.realPole;
            }
            set {
                for (int index = 0; index < cPolesCount; index++) {
                    float[] rPole = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        rPole[i] = value[index][i];
                    }
                    this.realPole.Add(rPole);
                }
            }
        }
        public List<float[]> ImaginaryPole {
            get {
                return this.imaginaryPole;
            }
            set {
                for (int index = 0; index < cPolesCount; index++) {
                    float[] iPole = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        iPole[i] = value[index][i];
                    }
                    this.imaginaryPole.Add(iPole);
                }
            }
        }
        public List<float[]> RealPoleError {
            get {
                return this.realPoleError;
            }
            set {
                for (int index = 0; index < cPolesCount; index++) {
                    float[] rPError = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        rPError[i] = value[index][i];
                    }
                    this.realPoleError.Add(rPError);
                }
            }
        }
        public List<float[]> ImaginaryPoleError {
            get {
                return this.imaginaryPoleError;
            }
            set {
                for (int index = 0; index < cPolesCount; index++) {
                    float[] iPError = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        iPError[i] = value[index][i];
                    }
                    this.imaginaryPoleError.Add(iPError);
                }
            }
        }
        #endregion

        #region constructors of Poles & Zeros
        public PolesNZeros() { }
        public PolesNZeros(
            byte[]  blockType,
            Int32   lenOfBlock,
            byte[]   _stageSignalInUnits,  
            byte[]   _stageSignalOutUnits, 
            float[]  aONormalizationFactor,
            float[]  normalizationFreq,    
            byte[]   numOfComplexZeros,    
            List<float[]>  realZero,             
            List<float[]>  imaginaryZero,        
            List<float[]>  realZeroError,        
            List<float[]>  imaginaryZeroError,   
            byte[]   numOfCompexPoles,     
            List<float[]>  realPole,            
            List<float[]>  imaginaryPole,        
            List<float[]>  realPoleError,        
            List<float[]>  imaginaryPoleError   
            )
            : base(blockType, lenOfBlock) {
                this.StageSignalInUnits     = _stageSignalInUnits;
                this.StageSignalOutUnits    = _stageSignalOutUnits;
                this.AONormalizationFactor  = aONormalizationFactor;
                this.NormalizationFreq      = normalizationFreq;
                this.NumOfComplexZeros      = numOfComplexZeros;
                this.RealZero               = realZero;
                this.ImaginaryZero          = imaginaryZero;
                this.RealZeroError          = imaginaryZeroError;
                this.NumOfComplexZeros      = numOfCompexPoles;
                this.RealPole               = realPole;
                this.ImaginaryPole          = imaginaryPole;
                this.RealPoleError          = realPoleError;
                this.ImaginaryPoleError     = imaginaryPoleError;
        }
        #endregion
    }
    #endregion

    #region A class[Named For050N052] for block[050]/[052]
    public abstract class For050N052 : Block {
        #region fields of For050N052
        private byte[] latitude  = new byte[10];//10B;D-Type;
        private byte[] longitude = new byte[11];//11B;D-Type;
        private byte[] elevation = new byte[7]; // 7B;D-Type;
        private char[] startDate = new char[22];//1-22B;V-Type;
        private char[] endDate   = new char[22];//1-22B;V-Type;
        #endregion

        #region properties of For050N052
        public char UpdateFlag  { get; set; }
        public byte[] Latitude  {
            get {
                return this.latitude;
            }
            set {
                int len = value.Length;
                len = (len > 10) ? 10 : len;
                for (int i = 0; i < len; i++) {
                    this.latitude[i] = value[i];
                }
            }
        }
        public byte[] Longitude {
            get {
                return this.longitude;
            }
            set {
                int len = value.Length;
                len = (len > 11) ? 11 : len;
                for (int i = 0; i < len; i++) {
                    this.longitude[i] = value[i];
                }
            }
        }
        public byte[] Elevation {
            get {
                return this.elevation;
            }
            set {
                int len = value.Length;
                len = (len > 7) ? 7 : len;
                for (int i = 0; i < len; i++) {
                    this.elevation[i] = value[i];
                }
            }
        }
        public string StartDate  {
            get {
                string _startDate = new string(startDate);
                return _startDate;
            }
            set {
                int len = value.Length;
                char[] str = new char[len];
                str = value.ToCharArray();
                len = (len > 22) ? 22 : len;
                for (int i = 0; i < len; i++) {
                    startDate[i] = str[i];
                }
            }
        }
        public string EndDate    {
            get {
                string _endDate = new string(endDate);
                return _endDate;
            }
            set {
                int len = value.Length;
                char[] str = new char[len];
                str = value.ToCharArray();
                len = (len > 22) ? 22 : len;
                for (int i = 0; i < len; i++) {
                    endDate[i] = str[i];
                }
            }
        }
        #endregion

        #region Constructors of For050N052
        public For050N052() { }
        public For050N052(
            byte[]  blockType,
            Int32   lenOfBlock,
            byte[]  _latitude,
            byte[]  _longitude,
            byte[]  _elevation,
            string  _startDate,
            string  _endDate,
            char    updateFlag
            )
            : base(blockType, lenOfBlock) {
                this.Latitude   = _latitude;
                this.Longitude  = _longitude;
                this.Elevation  = _elevation;
                this.StartDate  = _startDate;
                this.EndDate    = _endDate;
                this.UpdateFlag = updateFlag;
        }
        #endregion
    }
    #endregion

    #region A class[Named Coefficients] for blockettes which contain Coefficients information
    public abstract class Coefficients : Block {
        #region fields of Coefficients
        private byte[]    _signalInputUnits     = new byte[3]; // 3B;D-Type;
        private byte[]    _signalOutputUnits    = new byte[3]; // 3B;D-Type;
        private List<float[]>   numeratorCoefficient  = new List<float[]>();// 12B;F-Type;
        private List<float[]>   numeratorError        = new List<float[]>();// 12B;F-Type;
        private List<float[]>   denomiatorCoefficient = new List<float[]>();// 12B;F-Type;
        private List<float[]>   denominatiorError     = new List<float[]>();// 12B;F-Type;
        #endregion

        #region properties of Coefficients
        public Int32 NumOfNumerators    { get; set; }//Number of numerators:4B
        public Int32 NumOfDenominators  { get; set; }//Number of denominators:4B
        
        public byte[] SignalInputUnits  {
            get {
                return this._signalInputUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this._signalInputUnits[i] = value[i];
                }
            }
        } 
        public byte[] SignalOutputUnits {
            get {
                return this._signalOutputUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this._signalOutputUnits[i] = value[i];
                }
            }
        }
        public List<float[]> NumeratorCoefficient   {
            get {
                return this.numeratorCoefficient;
            }
            set {
                for (int index = 0; index < NumOfNumerators; index++) {
                    float[] numCoefficient = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        numCoefficient[i] = value[index][i];
                    }
                    this.numeratorCoefficient.Add(numCoefficient);
                }
            }
        }
        public List<float[]> NumeratorError         {
            get {
                return this.numeratorError;
            }
            set {
                for (int index = 0; index < NumOfNumerators; index++) {
                    float[] error = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        error[i] = value[index][i];
                    }
                    this.numeratorError.Add(error);
                }
            }
        }
        public List<float[]> DenominatorCofficient  {
            get {
                return this.denomiatorCoefficient;
            }
            set {
                for (int index = 0; index < NumOfDenominators; index++) {
                    float[] denomCoefficient = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        denomCoefficient[i] = value[index][i];
                    }
                    this.denomiatorCoefficient.Add(denomCoefficient);
                }
            }
        }
        public List<float[]> DenominatorError       {
            get {
                return this.denominatiorError;
            }
            set {
                for (int index = 0; index < NumOfDenominators; index++) {
                    float[] denomError = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        denomError[i] = value[index][i];
                    }
                    this.denominatiorError.Add(denomError);
                }
            }
        }
        #endregion

        #region constructors of Coefficients
        public Coefficients() { }
        public Coefficients(
            byte[]  blockType,
            Int32   lenOfBlock,
            byte[]  _signalInputUnits,    
            byte[]  _signalOutputUnits,   
            List<float[]> numeratorCoefficient, 
            List<float[]> numeratorError,       
            List<float[]> denomiatorCoefficient,
            List<float[]> denominatiorError,
            Int32   numOfNumerators,
            Int32   numOfDenominators
            )
            :base(blockType,lenOfBlock){
                this.NumOfNumerators        = numOfNumerators;
                this.NumeratorCoefficient   = numeratorCoefficient;
                this.NumeratorError         = numeratorError;
                this.NumOfDenominators      = numOfDenominators;
                this.DenominatorCofficient  = denomiatorCoefficient;
                this.DenominatorError       = denominatiorError;
                this.SignalInputUnits       = _signalInputUnits;
                this.SignalOutputUnits      = _signalOutputUnits;
        }
        #endregion
    }
    #endregion

    #region A class[Named _List] for blockettes which contain List information
    public abstract class _List : Block {
        #region fields of _list
        private byte[]  _signalInputUnits  = new byte[3]; // 3B;D-Type;
        private byte[]  _signalOutputUnits = new byte[3]; // 3B;D-Type;
        private List<float[]> frequency          = new List<float[]>();//12B;F-Type;
        private List<float[]> amplitude          = new List<float[]>();//12B;F-Type;
        private List<float[]> amplitudeError     = new List<float[]>();//12B;F-Type;
        private List<float[]> phaseAngle         = new List<float[]>();//12B;F-Type;
        private List<float[]> phaseError         = new List<float[]>();//12B;F-Type;
        #endregion

        #region properties of _list
        public Int32 NumOfRespListed   { get; set; }//Number of responses listed:4B
        public byte[] SignalInputUnits {
            get {
                return this._signalInputUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this._signalInputUnits[i] = value[i];
                }
            }
        }
        public byte[] SignalOutputUnits {
            get {
                return this._signalOutputUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this._signalOutputUnits[i] = value[i];
                }
            }
        }
        public List<float[]> Frequency {
            get {
                return this.frequency;
            }
            set {
                for (int index = 0; index < NumOfRespListed; index++) {
                    float[] _frequency = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        _frequency[i] = value[index][i];
                    }
                    this.frequency.Add(_frequency);
                }
            }
        }
        public List<float[]> Amplitude {
            get {
                return this.amplitude;
            }
            set {
                for (int index = 0; index < NumOfRespListed; index++) {
                    float[] _amplitude = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        _amplitude[i] = value[index][i];
                    }
                    this.amplitude.Add(_amplitude);
                }
            }
        }
        public List<float[]> AmplitudeError {
            get {
                return this.amplitudeError;
            }
            set {
                for (int index = 0; index < NumOfRespListed; index++) {
                    float[] _amplitudeError = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        _amplitudeError[i] = value[index][i];
                    }
                    this.amplitudeError.Add(_amplitudeError);
                }
            }
        }
        public List<float[]> PhaseAngle {
            get {
                return this.phaseAngle;
            }
            set {
                for (int index = 0; index < NumOfRespListed; index++) {
                    float[] _phaseAngle = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        _phaseAngle[i] = value[index][i];
                    }
                    this.phaseAngle.Add(_phaseAngle);
                }
            }
        }
        public List<float[]> PhaseError {
            get {
                return this.phaseError;
            }
            set {
                for (int index = 0; index < NumOfRespListed; index++) {
                    float[] _phaseError = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        _phaseError[i] = value[index][i];
                    }
                    this.phaseError.Add(_phaseError);
                }
            }
        }
        #endregion

        #region constructors of _list
        public _List() { }
        public _List(
            byte[]  blockType,
            Int32   lenOfBlock,           
            byte[]  _signalInputUnits,
            byte[]  _signalOutputUnits,
            List<float[]> frequency,
            List<float[]> amplitude,
            List<float[]> amplitudeError,
            List<float[]> phaseAngle,
            List<float[]> phaseError,
            Int32   numOfRespListed
            )
            : base(blockType, lenOfBlock){
                this.SignalInputUnits   = _signalInputUnits;
                this.SignalOutputUnits  = _signalOutputUnits;
                this.Frequency          = frequency;
                this.Amplitude          = amplitude;
                this.AmplitudeError     = amplitudeError;
                this.PhaseAngle         = phaseAngle;
                this.PhaseError         = phaseError;
                this.NumOfRespListed    = numOfRespListed;
        }
        #endregion
    }
    #endregion

    #region A class[Named _Generic] for blockettes which contain Generic information
    public abstract class _Generic : Block {
        #region fields of _Generic
        private byte[]  _signalInputUnits  = new byte[3]; // 3B;D-Type;
        private byte[]  _signalOutputUnits = new byte[3]; // 3B;D-Type;
        private List<float[]> cornerFreq         = new List<float[]>();// 3B;F-Type;
        private List<float[]> cornerSlope        = new List<float[]>();// 3B;F-Type;
        #endregion

        #region properties of _Generic
        public Int32 NumOfCornerListed { get; set; }//Number of corners listed:4B
        public List<float[]> CornerFreq {
            get {
                return this.cornerFreq;
            }
            set {
                for (int index = 0; index < NumOfCornerListed; index++) {
                    float[] _cornerFreq = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        _cornerFreq[i] = value[index][i];
                    }
                    this.cornerFreq.Add(_cornerFreq);
                }
            }
        }
        public List<float[]> CornerSlope {
            get {
                return this.cornerSlope;
            }
            set {
                for (int index = 0; index < NumOfCornerListed; index++) {
                    float[] _cornerSlope = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        _cornerSlope[i] = value[index][i];
                    }
                    this.cornerSlope.Add(_cornerSlope);
                }
            }
        }
        public byte[] SignalInputUnits {
            get {
                return this._signalInputUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this._signalInputUnits[i] = value[i];
                }
            }
        }
        public byte[] SignalOutputUnits {
            get {
                return this._signalOutputUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this._signalOutputUnits[i] = value[i];
                }
            }
        }
        #endregion

        #region constructors of _Generic
        public _Generic() { }
        public _Generic(
            byte[]  blockType,
            Int32   lenOfBlock,
            byte[]  signalInputUnits,
            byte[]  signalOutputUnits,
            Int32   numOfCornersListed,
            List<float[]> cornerFreq,
            List<float[]> cornerSlope
            )
            : base(blockType, lenOfBlock) {
                this.NumOfCornerListed  = numOfCornersListed;
                this.SignalInputUnits   = _signalInputUnits;
                this.SignalOutputUnits  = _signalOutputUnits;
                this.CornerFreq         = cornerFreq;
                this.CornerSlope        = cornerSlope;
        }
        #endregion
    }
    #endregion

    #region A class[Named Decimation] for blockettes which contain Decimation information
    public abstract class Decimation : Block {
        #region fields of Decimation
        private byte[] inputSampleRate    = new byte[10];//Input sample rate:10B
        private byte[] decimationFactor   = new byte[5]; //Decimation factor:5B
        private byte[] decimationOffset   = new byte[5]; //Decimation offset:5B
        private byte[] estimatedDelay     = new byte[11];//Estimated delay (seconds):11B
        private byte[] correctionApplied  = new byte[11];//Correction applied (seconds):11B
        #endregion

        #region properties of Decimation
        public byte[] InputSampleRate {
            get {
                return this.inputSampleRate;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.inputSampleRate[i] = value[i];
                }
            }
        }
        public byte[] DecimationFactor {
            get {
                return this.decimationFactor;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.decimationFactor[i] = value[i];
                }
            }
        }
        public byte[] DecimationOffset {
            get {
                return this.decimationOffset;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.decimationOffset[i] = value[i];
                }
            }
        }
        public byte[] EstimatedDelay {
            get {
                return this.estimatedDelay;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.estimatedDelay[i] = value[i];
                }
            }
        }
        public byte[] CorrectionApplied {
            get {
                return this.correctionApplied;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.correctionApplied[i] = value[i];
                }
            }
        }
        #endregion

        #region constructors of Decimation
        public Decimation() { }
        public Decimation(
            byte[]  blockType,
            Int32   lenOfBlock,
            byte[]  _inputSampleRate, 
            byte[]  _decimationFactor, 
            byte[]  _decimationOffset, 
            byte[]  _estimatedDelay, 
            byte[]  _correctionApplied
            )
            : base(blockType, lenOfBlock) {
                this.InputSampleRate    = _inputSampleRate;
                this.DecimationFactor   = _decimationFactor; 
                this.DecimationOffset   = _decimationOffset; 
                this.EstimatedDelay     = _estimatedDelay;   
                this.CorrectionApplied  = _correctionApplied;
        }
        #endregion
    }
    #endregion

    #region A class[Named SensitivityNGain] for blockette which contain Sensitivity/Gain information
    public abstract class SensitivityNGain : Block {
        #region fields of SensitivityNGain
        private float[]  sensitivityNGain       = new float[3]; // 12B;Sensitivity/gain
        private float[]  frequency              = new float[3]; // 12B;Frequency (Hz)
        private List<char[]>   timeOfAboveCalibration = new List<char[]>(); //Time of above calibration:1-22B
        private List<float[]>  sensitForCalibration   = new List<float[]>(); // 12B;Sensitivity for calibration
        private List<float[]>  freqOfCalibrationSens  = new List<float[]>(); // 12B;Frequency of calibration sensitivity
        #endregion

        #region properties of SensitivityNGain
        public Int16 NumOfHistoryValues { get; set; }   //Number of history values:2B
        public float[] _SensitivityNGain       {
            get {
                return this.sensitivityNGain;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.sensitivityNGain[i] = value[i];
                }
            }
        }   
        public float[] Frequency             {
            get {
                return this.frequency;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.frequency[i] = value[i];
                }
            }
        }   
        public List<float[]> SensitForCalibration  {
            get {
                return this.sensitForCalibration;
            }
            set {
                for (int index = 0; index < NumOfHistoryValues; index++) {
                    float[] _sensitForCalibration = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        _sensitForCalibration[i] = value[index][i];
                    }
                    this.sensitForCalibration.Add(_sensitForCalibration);
                }
            }
        }   
        public List<float[]> FreqOfCalibrationSens {
            get {
                return this.freqOfCalibrationSens;
            }
            set {
                for (int index = 0; index < NumOfHistoryValues; index++) {
                    float[] _freqOfCalibrationSens = new float[3];
                    int len = value[index].Length;
                    len = (len > 3) ? 3 : len;
                    for (int i = 0; i < len; i++) {
                        _freqOfCalibrationSens[i] = value[index][i];
                    }
                    this.freqOfCalibrationSens.Add(_freqOfCalibrationSens);
                }
            }
        }
        public List<char[]> TimeOfAboveCalibration {                  //Response Name:1-25B
            get {
                return timeOfAboveCalibration;
            }
            set {
                for (int i = 0; i < NumOfHistoryValues; i++) {
                    int len = value[i].Length;
                    len = (len > 22) ? 22 : len;
                    char[] _timeOfAboveCalibration = new char[len];
                    for (int j = 0; j < len; j++) {
                        _timeOfAboveCalibration[j] = value[i][j];
                    }
                    this.timeOfAboveCalibration.Add(_timeOfAboveCalibration);
                }
            }
        }
        #endregion

        #region constructors of SensitivityNGain
        public SensitivityNGain() { }
        public SensitivityNGain(
            byte[]  blockType,
            Int32   lenOfBlock,
            List<char[]>  _timeOfAboveCalibration,
            float[] _sensitivityNGain,      
            float[] _frequency,             
            List<float[]> _sensitForCalibration,  
            List<float[]> _freqOfCalibrationSens 
            )
            :base(blockType,lenOfBlock){
                this.timeOfAboveCalibration = _timeOfAboveCalibration;
                this._SensitivityNGain      = _sensitivityNGain;
                this.frequency              = _frequency;
                this.sensitForCalibration   = _sensitForCalibration;
                this.freqOfCalibrationSens  = _freqOfCalibrationSens;
        }
        #endregion
    }
    #endregion

    #region A class[Named FIR] for blockette which contain FIR information
    public abstract class FIR : Block {
        #region fields of FIR
        private char[] respName         = new char[25]; // 1-25 Bytes;
        private byte[] signalInUnits    = new byte[3];  // 3B;D-Type
        private byte[] signalOutUnits   = new byte[3];  // 3B;D-Type
        private List<byte[]> _FIRCoefficient = new List<byte[]>(); //14B;float-Type;
        #endregion

        #region properties of FIR
        public Char  SymmetryCode { get; set; }//Symmetry Code:1B
        public Int32 NumOfFIR     { get; set; }//Number of Factors:4B
        public byte[] SignalInUnits     {
            get {
                return this.signalInUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.signalInUnits[i] = value[i];
                }
            }
        }
        public byte[] SignalOutUnits    {
            get {
                return this.signalOutUnits;
            }
            set {
                int len = value.Length;
                len = (len > 3) ? 3 : len;
                for (int i = 0; i < len; i++) {
                    this.signalOutUnits[i] = value[i];
                }
            }
        }
        public string RespName {
            get {
                string _respName = new string(respName);
                return _respName;
            }
            set {
                int len = value.Length;
                char[] str = new char[len];
                str = value.ToCharArray();
                len = (len > 25) ? 25 : len;
                for (int i = 0; i < len; i++) {
                    respName[i] = str[i];
                }
            }
        }
        public List<byte[]> FIRCoefficient {
            get {
                return this._FIRCoefficient;
            }
            set {
                for (int index = 0; index < NumOfFIR; index++) {
                    byte[] numOfFactors = new byte[14];
                    int len = value[index].Length;
                    len = (len > 14) ? 14 : len;
                    for (int i = 0; i < len; i++) {
                        numOfFactors[i] = value[index][i];
                    }
                    this.FIRCoefficient.Add(numOfFactors);
                }
                
                
                
            }
        }
        #endregion

        #region constructors of FIR
        public FIR() { }
        public FIR(
            byte[] blockType,
            Int32  lenOfBlock,
            char[] _respName,       
            byte[] _signalInUnits,  
            byte[] _signalOutUnits,
            Char   symmetryCode,
            Int32  numOfFIR,
            List<byte[]> _FIRCoefficient
            )
            : base(blockType, lenOfBlock) {
                this.respName       = _respName;
                this.FIRCoefficient = _FIRCoefficient;
                this.SignalInUnits  = _signalInUnits;
                this.SignalOutUnits = _signalOutUnits;
                this.SymmetryCode   = symmetryCode;
                this.NumOfFIR       = numOfFIR;
        }
        #endregion
    }
    #endregion

    #region A class[Named NBlock] for blockette of DataRecord which contain blockette type & next blockette's byte number
    public abstract class NBlock{
        public byte  ReservedByte       { get; set; }
        public Int16 BlockType          { get; set; }
        public Int16 NextBlockByteNum   { get; set; } //2B;B-Type;Next blockette’s byte number

        public NBlock(){}
        public NBlock(Int16 blockType,Int16 nextBlockByteNum,byte reservedByte){
            this.BlockType         = blockType;
            this.ReservedByte      = reservedByte;
            this.NextBlockByteNum  = nextBlockByteNum;
        }
    }
    #endregion

    #region A class[Named Calibration] for blockette which contain Calibration information
    public abstract class Calibration : NBlock {
        #region fields of Calibration
        private byte[] beginOfCalibrationTime  = new byte[10];// 10B;Beginning of calibration time
        private char[] chaWithCalibrationInput = new char[3]; // 3B;Channel with calibration input
        private char[] coupling = new char[12];  // 12B;Coupling
        private char[] rolloff  = new char[12];  // 12B;Rolloff
        #endregion

        #region properties of Calibration
        public Byte     CalibrationFlags{ get; set; }//Calibration flags:1B
        public float    XDuration       { get; set; }//Interval duration:4B
        public float    RefAmplitude    { get; set; }//Reference amplitude:4B
        public byte[] BeginOfCalibrationTime {
            get {
                return this.beginOfCalibrationTime;
            }
            set {
                int len = value.Length;
                len = (len > 10) ? 10 : len;
                for (int i = 0; i < len; i++) {
                    this.beginOfCalibrationTime[i] = value[i];
                }
            }
        }
        public string ChaWithCalibrationInput { //Channel with calibration input:3B
            get {
                string _calInputChannel = new string(chaWithCalibrationInput);
                return _calInputChannel;
            }
            set {
                int Len = value.Length;
                char[] str = new char[Len];
                str = value.ToCharArray();
                Len = (3 < Len) ? 3 : Len;
                for (int i = 0; i < Len; i++)
                    chaWithCalibrationInput[i] = str[i];
            }
        }
        public string Coupling { //Coupling:12B
            get {
                string _coupling = new string(coupling);
                return _coupling;
            }
            set {
                int Len = value.Length;
                char[] str = new char[Len];
                str = value.ToCharArray();
                Len = (12 < Len) ? 12 : Len;
                for (int i = 0; i < Len; i++)
                    coupling[i] = str[i];
            }
        }
        public string Rolloff { //Rolloff:12B
            get {
                string _rolloff = new string(rolloff);
                return _rolloff;
            }
            set {
                int Len = value.Length;
                char[] str = new char[Len];
                str = value.ToCharArray();
                Len = (12 < Len) ? 12 : Len;
                for (int i = 0; i < Len; i++)
                    rolloff[i] = str[i];
            }
        }
        #endregion

        #region constructors of Calibration
        public Calibration() { }
        public Calibration(
            Int16   blockType,
            Int16   nextBlockByteNum,
            byte    reservedByte,
            byte[]  beginOfCalTime,
            byte    calibrationFlags,
            float   xDuration,
            string  chaWithCalibrationInput,
            float   refAmplitude,
            string  coupling,
            string  rolloff
            )
            : base(blockType, nextBlockByteNum, reservedByte) {
                this.BeginOfCalibrationTime     = beginOfCalibrationTime;
                this.CalibrationFlags           = calibrationFlags;
                this.ChaWithCalibrationInput    = chaWithCalibrationInput;
                this.XDuration      = xDuration;
                this.RefAmplitude   = refAmplitude;
                this.Coupling       = coupling;
                this.Rolloff        = rolloff;
        }
        #endregion
    }
    #endregion
}
